#pragma once

#include "traits.h"

#include <stlcompat/span.h>

#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <string_view>
#include <vector>

namespace serializer
{

// ============================================================================
// 简单的内存写入器实现
// ============================================================================

/**
 * 基于vector的简单写入器
 * 用于测试和演示CPO机制
 */
class vector_writer
{
public:
    /**
     * 构造函数
     */
    vector_writer() = default;

    /**
     * 写入原始字节数据
     * @param data 要写入的数据指针
     * @param size 要写入的字节数
     * @throws std::runtime_error 如果写入失败
     */
    void write_bytes(const std::byte * data, std::size_t size)
    {
        if (data == nullptr && size > 0)
        {
            throw std::runtime_error("Invalid data pointer");
        }

        // 使用insert一次性插入所有数据，性能优于逐字节push_back
        buffer_.insert(buffer_.end(), data, data + size);
    }

    /**
     * 写入字节数据（span版本）
     */
    void write_bytes(kp::span<const std::byte> data) { write_bytes(data.data(), data.size()); }

    /**
     * 写入字符串视图
     * @param str 要写入的字符串视图
     * @throws std::runtime_error 如果写入失败
     */
    void write_string_view(std::string_view str)
    {
        const auto * bytes = reinterpret_cast<const std::byte *>(str.data());
        write_bytes(bytes, str.size());
    }

    /**
     * 获取当前写入位置
     * @return 当前位置（等同于已写入的字节数）
     */
    std::size_t position() const noexcept { return buffer_.size(); }

    /**
     * 获取已写入的总字节数
     * @return 已写入的字节数
     */
    std::size_t bytes_written() const noexcept { return buffer_.size(); }

    /**
     * 检查是否还能写入指定大小的数据
     * @param size 要检查的大小
     * @return 总是返回true（内存写入器可以动态扩展）
     */
    bool can_write(std::size_t size) const noexcept { return true; }

    /**
     * 获取写入的数据
     * @return 数据的常量引用
     */
    const std::vector<std::byte> & data() const noexcept { return buffer_; }

    /**
     * 获取数据的只读span视图（零拷贝）
     * @return 已写入数据的span
     */
    kp::span<const std::byte> written_data() const noexcept
    {
        return kp::span<const std::byte>(buffer_.data(), buffer_.size());
    }

    /**
     * 清空缓冲区
     */
    void clear() noexcept { buffer_.clear(); }

private:
    std::vector<std::byte> buffer_;
};

// ============================================================================
// 简单的内存读取器实现
// ============================================================================

/**
 * 基于vector的简单读取器
 * 用于测试和演示CPO机制
 */
class vector_reader
{
public:
    /**
     * 构造函数
     * @param data 要读取的数据
     */
    explicit vector_reader(const std::vector<std::byte> & data) : data_(data), position_(0) {}

    /**
     * 构造函数
     * @param data 要读取的数据（移动语义）
     */
    explicit vector_reader(std::vector<std::byte> && data) : data_(std::move(data)), position_(0) {}

    /**
     * 读取原始字节数据
     * @param data 读取数据的目标缓冲区
     * @param size 要读取的字节数
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    void read_bytes(std::byte * data, std::size_t size)
    {
        if (data == nullptr && size > 0)
        {
            throw std::runtime_error("Invalid data pointer");
        }

        if (position_ + size > data_.size())
        {
            throw std::runtime_error("Not enough data to read");
        }

        // 使用std::copy一次性复制所有数据，性能优于逐字节复制
        std::copy(data_.begin() + position_, data_.begin() + position_ + size, data);
        position_ += size;
    }

    /**
     * 读取到字节span
     */
    void read_bytes(kp::span<std::byte> span_bytes)
    {
        read_bytes(span_bytes.data(), span_bytes.size());
    }

    /**
     * 读取到uint8_t数组
     * @param data uint8_t数组
     */
    template <std::size_t N>
    void read_bytes(std::array<std::uint8_t, N> & data)
    {
        read_bytes(reinterpret_cast<std::byte *>(data.data()), data.size());
    }

    /**
     * 读取字符串
     * @param size 要读取的字符串长度
     * @return 读取的字符串
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    std::string read_string(std::size_t size)
    {
        if (position_ + size > data_.size())
        {
            throw std::runtime_error("Not enough data to read");
        }

        std::string result;
        result.resize(size);
        const auto * bytes = reinterpret_cast<const char *>(data_.data() + position_);
        std::copy(bytes, bytes + size, result.begin());
        position_ += size;
        return result;
    }

    /**
     * 获取当前读取位置
     * @return 当前位置
     */
    std::size_t position() const noexcept { return position_; }

    /**
     * 检查是否还有数据可读
     * @return 如果还有数据返回true
     */
    bool has_data() const noexcept { return position_ < data_.size(); }

    /**
     * 获取剩余可读字节数
     * @return 剩余字节数
     */
    std::size_t remaining_bytes() const noexcept { return data_.size() - position_; }

    /**
     * 检查是否还能读取指定大小的数据
     * @param size 要检查的大小
     * @return 如果能读取返回true
     */
    bool can_read(std::size_t size) const noexcept { return position_ + size <= data_.size(); }

    /**
     * 获取数据的总大小
     * @return 数据总大小
     */
    std::size_t size() const noexcept { return data_.size(); }

    /**
     * 设置读取位置
     * @param pos 新的位置
     * @throws std::runtime_error 如果位置无效
     */
    void seek(std::size_t pos)
    {
        if (pos > data_.size())
        {
            throw std::runtime_error("Invalid seek position");
        }
        position_ = pos;
    }

private:
    std::vector<std::byte> data_;
    std::size_t position_;
};

// ============================================================================
// 基于span的零拷贝读取器实现
// ============================================================================

/**
 * 基于span的零拷贝读取器
 * 直接操作现有内存，无需额外拷贝
 */
class span_reader
{
public:
    /**
     * 构造函数
     * @param data 要读取的数据span
     */
    explicit span_reader(kp::span<const std::byte> data) : data_(data), position_(0) {}

    /**
     * 从uint8_t数组构造
     * @param buffer uint8_t数组
     */
    template <std::size_t N>
    explicit span_reader(const std::array<std::uint8_t, N> & buffer)
        : data_(reinterpret_cast<const std::byte *>(buffer.data()), buffer.size()), position_(0)
    {
    }

    /**
     * 从原始指针和大小构造
     * @param data 数据指针
     * @param size 数据大小
     */
    span_reader(const std::byte * data, std::size_t size) : data_(data, size), position_(0) {}

    /**
     * 从vector构造
     * @param vec 数据vector
     */
    explicit span_reader(const std::vector<std::byte> & vec)
        : data_(kp::span<const std::byte>(vec.data(), vec.size())), position_(0)
    {
    }

    /**
     * 读取原始字节数据
     * @param data 读取数据的目标缓冲区
     * @param size 要读取的字节数
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    void read_bytes(std::byte * data, std::size_t size)
    {
        if (data == nullptr && size > 0)
        {
            throw std::runtime_error("Invalid data pointer");
        }

        if (position_ + size > data_.size())
        {
            throw std::runtime_error("Not enough data to read");
        }

        // 零拷贝：直接从span复制到目标缓冲区
        std::copy(data_.begin() + position_, data_.begin() + position_ + size, data);
        position_ += size;
    }

    /**
     * 读取到字节span
     * @param data 目标字节span
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    void read_bytes(kp::span<std::byte> span_bytes)
    {
        read_bytes(span_bytes.data(), span_bytes.size());
    }

    /**
     * 读取到uint8_t数组
     * @param data uint8_t数组
     */
    template <std::size_t N>
    void read_bytes(std::array<std::uint8_t, N> & data)
    {
        read_bytes(reinterpret_cast<std::byte *>(data.data()), data.size());
    }

    /**
     * 零拷贝读取：直接返回数据的span视图
     * @param size 要读取的字节数
     * @return 数据的span视图
     * @throws std::runtime_error 如果数据不足
     */
    kp::span<const std::byte> read_span(std::size_t size)
    {
        if (position_ + size > data_.size())
        {
            throw std::runtime_error("Not enough data to read");
        }

        auto result = kp::span<const std::byte>(data_.data() + position_, size);
        position_ += size;
        return result;
    }

    /**
     * 读取字符串
     * @param size 要读取的字符串长度
     * @return 读取的字符串
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    std::string read_string(std::size_t size)
    {
        if (position_ + size > data_.size())
        {
            throw std::runtime_error("Not enough data to read");
        }

        std::string result;
        result.resize(size);
        const auto * bytes = reinterpret_cast<const char *>(data_.data() + position_);
        std::copy(bytes, bytes + size, result.begin());
        position_ += size;
        return result;
    }

    /**
     * 零拷贝读取字符串视图
     * @param size 要读取的字符串长度
     * @return 字符串视图
     * @throws std::runtime_error 如果数据不足
     */
    std::string_view read_string_view(std::size_t size)
    {
        if (position_ + size > data_.size())
        {
            throw std::runtime_error("Not enough data to read");
        }

        const auto * chars = reinterpret_cast<const char *>(data_.data() + position_);
        position_ += size;
        return std::string_view(chars, size);
    }

    /**
     * 获取当前读取位置
     * @return 当前位置
     */
    std::size_t position() const noexcept { return position_; }

    /**
     * 检查是否还有数据可读
     * @return 如果还有数据返回true
     */
    bool has_data() const noexcept { return position_ < data_.size(); }

    /**
     * 获取剩余可读字节数
     * @return 剩余字节数
     */
    std::size_t remaining_bytes() const noexcept { return data_.size() - position_; }

    /**
     * 获取数据的总大小
     * @return 数据总大小
     */
    std::size_t size() const noexcept { return data_.size(); }

    /**
     * 设置读取位置
     * @param pos 新的位置
     * @throws std::runtime_error 如果位置无效
     */
    void seek(std::size_t pos)
    {
        if (pos > data_.size())
        {
            throw std::runtime_error("Invalid seek position");
        }
        position_ = pos;
    }

    /**
     * 检查是否能读取指定大小的数据
     * @param size 要检查的数据大小
     * @return 如果能读取返回true
     */
    bool can_read(std::size_t size) const noexcept { return position_ + size <= data_.size(); }

private:
    kp::span<const std::byte> data_;
    std::size_t position_;
};

// ============================================================================
// 基于缓冲区的写入器实现
// ============================================================================

/**
 * 基于固定缓冲区的写入器
 * 写入到预分配的缓冲区，避免动态内存分配
 */
class buffer_writer
{
public:
    /**
     * 构造函数
     */
    explicit buffer_writer(kp::span<std::byte> buffer) : buffer_(buffer), position_(0) {}

    template <std::size_t N>
    explicit buffer_writer(std::array<std::uint8_t, N> & buffer)
        : buffer_(reinterpret_cast<std::byte *>(buffer.data()), buffer.size()), position_(0)
    {
    }

    buffer_writer(std::byte * data, std::size_t size) : buffer_(data, size), position_(0) {}

    void write_bytes(const std::byte * data, std::size_t size)
    {
        if (data == nullptr && size > 0)
        {
            throw std::runtime_error("Invalid data pointer");
        }
        if (position_ + size > buffer_.size())
        {
            throw std::runtime_error("Buffer overflow: not enough space");
        }
        std::copy(data, data + size, buffer_.begin() + position_);
        position_ += size;
    }

    /** 从字节span写入 */
    void write_bytes(kp::span<const std::byte> data) { write_bytes(data.data(), data.size()); }

    template <std::size_t N>
    void write_bytes(const std::array<std::uint8_t, N> & data)
    {
        write_bytes(reinterpret_cast<const std::byte *>(data.data()), data.size());
    }

    void write_string(const std::string & str)
    {
        const auto * bytes = reinterpret_cast<const std::byte *>(str.data());
        write_bytes(bytes, str.size());
    }
    void write_string(std::string_view str)
    {
        const auto * bytes = reinterpret_cast<const std::byte *>(str.data());
        write_bytes(bytes, str.size());
    }
    void fill_bytes(std::byte value, std::size_t count)
    {
        if (position_ + count > buffer_.size())
        {
            throw std::runtime_error("Buffer overflow: not enough space");
        }
        std::fill_n(buffer_.begin() + position_, count, value);
        position_ += count;
    }

    std::size_t position() const noexcept { return position_; }
    std::size_t bytes_written() const noexcept { return position_; }
    std::size_t remaining_space() const noexcept { return buffer_.size() - position_; }
    std::size_t capacity() const noexcept { return buffer_.size(); }
    bool has_space() const noexcept { return position_ < buffer_.size(); }

    /** 已写入数据的只读视图 */
    kp::span<const std::byte> written_data() const noexcept
    {
        return kp::span<const std::byte>(buffer_.data(), position_);
    }

    /** 剩余空间视图 */
    kp::span<std::byte> remaining_buffer() noexcept
    {
        return kp::span<std::byte>(buffer_.data() + position_, buffer_.size() - position_);
    }

    void seek(std::size_t pos)
    {
        if (pos > buffer_.size())
        {
            throw std::runtime_error("Invalid seek position");
        }
        position_ = pos;
    }

    void clear() noexcept { position_ = 0; }

    void write_string_view(std::string_view str)
    {
        const auto * bytes = reinterpret_cast<const std::byte *>(str.data());
        write_bytes(bytes, str.size());
    }

    bool can_write(std::size_t size) const noexcept { return position_ + size <= buffer_.size(); }

private:
    kp::span<std::byte> buffer_;
    std::size_t position_;
};

// ============================================================================
// 基于流的I/O适配器实现
// ============================================================================

/**
 * 基于标准流的写入器
 * 支持写入到任何标准输出流
 */
class stream_writer
{
public:
    /**
     * 构造函数
     * @param stream 输出流引用
     */
    explicit stream_writer(std::ostream & stream) : stream_(stream), bytes_written_(0) {}

    /**
     * 写入原始字节数据
     * @param data 要写入的数据
     * @param size 要写入的字节数
     * @throws std::runtime_error 如果写入失败
     */
    void write_bytes(const std::byte * data, std::size_t size)
    {
        if (data == nullptr && size > 0)
        {
            throw std::runtime_error("Invalid data pointer");
        }
        if (size == 0)
        {
            return;
        }
        const auto * char_data = reinterpret_cast<const char *>(data);
        stream_.write(char_data, static_cast<std::streamsize>(size));
        if (!stream_.good())
        {
            throw std::runtime_error("Stream write failed");
        }
        bytes_written_ += size;
    }

    /** 从字节span写入 */
    void write_bytes(kp::span<const std::byte> data) { write_bytes(data.data(), data.size()); }

    template <std::size_t N>
    void write_bytes(const std::array<std::uint8_t, N> & data)
    {
        write_bytes(reinterpret_cast<const std::byte *>(data.data()), data.size());
    }

    /**
     * 写入字符串
     * @param str 要写入的字符串
     * @throws std::runtime_error 如果写入失败
     */
    void write_string(const std::string & str)
    {
        stream_ << str;
        if (!stream_.good())
        {
            throw std::runtime_error("Stream write failed");
        }
        bytes_written_ += str.size();
    }

    /**
     * 写入字符串视图
     * @param str 要写入的字符串视图
     * @throws std::runtime_error 如果写入失败
     */
    void write_string(std::string_view str)
    {
        stream_.write(str.data(), static_cast<std::streamsize>(str.size()));
        if (!stream_.good())
        {
            throw std::runtime_error("Stream write failed");
        }
        bytes_written_ += str.size();
    }

    /**
     * 批量写入：填充指定字节值
     * @param value 要填充的字节值
     * @param count 填充次数
     * @throws std::runtime_runtime 如果写入失败
     */
    void fill_bytes(std::byte value, std::size_t count)
    {
        const char char_value = static_cast<char>(value);
        for (std::size_t i = 0; i < count; ++i)
        {
            stream_.put(char_value);
        }

        if (!stream_.good())
        {
            throw std::runtime_error("Stream write failed");
        }

        bytes_written_ += count;
    }

    /**
     * 刷新流缓冲区
     * @throws std::runtime_error 如果刷新失败
     */
    void flush()
    {
        stream_.flush();
        if (!stream_.good())
        {
            throw std::runtime_error("Stream flush failed");
        }
    }

    /**
     * 获取已写入的字节数
     * @return 已写入字节数
     */
    std::size_t bytes_written() const noexcept { return bytes_written_; }

    /**
     * 检查流状态是否良好
     * @return 如果流状态良好返回true
     */
    bool good() const noexcept { return stream_.good(); }

    /**
     * 写入字符串视图
     * @param str 要写入的字符串视图
     * @throws std::runtime_error 如果写入失败
     */
    void write_string_view(std::string_view str)
    {
        stream_.write(str.data(), static_cast<std::streamsize>(str.size()));
        if (!stream_.good())
        {
            throw std::runtime_error("Stream write failed");
        }
        bytes_written_ += str.size();
    }

    /**
     * 检查是否能写入指定大小的数据
     * 对于流写入器，总是返回true（除非流状态不好）
     * @param size 要检查的数据大小
     * @return 如果流状态良好返回true
     */
    bool can_write(std::size_t size) const noexcept
    {
        (void)size; // 未使用的参数
        return stream_.good();
    }

private:
    std::ostream & stream_;
    std::size_t bytes_written_;
};

/**
 * 基于标准流的读取器
 * 支持从任何标准输入流读取
 */
class stream_reader
{
public:
    /**
     * 构造函数
     * @param stream 输入流引用
     */
    explicit stream_reader(std::istream & stream) : stream_(stream), bytes_read_(0) {}

    /**
     * 读取原始字节数据
     * @param data 读取数据的目标缓冲区
     * @param size 要读取的字节数
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    void read_bytes(std::byte * data, std::size_t size)
    {
        if (data == nullptr && size > 0)
        {
            throw std::runtime_error("Invalid data pointer");
        }

        if (size == 0)
        {
            return;
        }

        // 转换为char*进行流读取
        auto * char_data = reinterpret_cast<char *>(data);
        stream_.read(char_data, static_cast<std::streamsize>(size));

        if (stream_.gcount() != static_cast<std::streamsize>(size))
        {
            throw std::runtime_error("Not enough data to read from stream");
        }

        bytes_read_ += size;
    }

    /** 读取到字节span */
    void read_bytes(kp::span<std::byte> span_bytes)
    {
        read_bytes(span_bytes.data(), span_bytes.size());
    }

    /**
     * 读取到uint8_t数组
     * @param data uint8_t数组
     */
    template <std::size_t N>
    void read_bytes(std::array<std::uint8_t, N> & data)
    {
        read_bytes(reinterpret_cast<std::byte *>(data.data()), data.size());
    }

    /**
     * 读取字符串
     * @param size 要读取的字符串长度
     * @return 读取的字符串
     * @throws std::runtime_error 如果读取失败或数据不足
     */
    std::string read_string(std::size_t size)
    {
        std::string result;
        result.resize(size);
        stream_.read(result.data(), static_cast<std::streamsize>(size));

        if (stream_.gcount() != static_cast<std::streamsize>(size))
        {
            throw std::runtime_error("Not enough data to read from stream");
        }

        bytes_read_ += size;
        return result;
    }

    /**
     * 读取一行文本
     * @return 读取的行（不包含换行符）
     * @throws std::runtime_error 如果读取失败
     */
    std::string read_line()
    {
        std::string line;
        if (!std::getline(stream_, line))
        {
            throw std::runtime_error("Failed to read line from stream");
        }
        bytes_read_ += line.size() + 1; // +1 for newline
        return line;
    }

    /**
     * 批量读取：读取到vector
     * @param size 要读取的字节数
     * @return 读取的数据vector
     * @throws std::runtime_error 如果读取失败
     */
    std::vector<std::byte> read_bytes_vector(std::size_t size)
    {
        std::vector<std::byte> result(size);
        read_bytes(result.data(), size);
        return result;
    }

    /**
     * 获取已读取的字节数
     * @return 已读取字节数
     */
    std::size_t bytes_read() const noexcept { return bytes_read_; }

    /**
     * 检查流状态是否良好
     * @return 如果流状态良好返回true
     */
    bool good() const noexcept { return stream_.good(); }

    /**
     * 检查是否到达流末尾
     * @return 如果到达末尾返回true
     */
    bool eof() const noexcept { return stream_.eof(); }

    /**
     * 检查是否还有数据可读
     * @return 如果还有数据返回true
     */
    bool has_data() const noexcept
    {
        if (!stream_.good())
            return false;

        // 使用peek来检查是否真的有数据可读
        // 这会触发EOF标志的设置如果已经到达流末尾
        auto peek_result = stream_.peek();
        return peek_result != std::istream::traits_type::eof();
    }

    /**
     * 获取剩余可读字节数
     * 对于流读取器，无法准确知道剩余字节数，返回最大值表示未知
     * @return 剩余字节数（流的情况下返回最大值）
     */
    std::size_t remaining_bytes() const noexcept
    {
        // 对于流，我们无法准确知道剩余字节数
        return has_data() ? std::numeric_limits<std::size_t>::max() : 0;
    }

    /**
     * 检查是否能读取指定大小的数据
     * 对于流读取器，只能检查流状态
     * @param size 要检查的数据大小
     * @return 如果流状态良好返回true
     */
    bool can_read(std::size_t size) const noexcept
    {
        (void)size; // 未使用的参数
        return has_data();
    }

private:
    std::istream & stream_;
    std::size_t bytes_read_;
};

// ============================================================================
// 概念验证
// ============================================================================

// 验证我们的实现满足概念要求
static_assert(writer<vector_writer>);
static_assert(reader<vector_reader>);
static_assert(extended_writer<vector_writer>);
static_assert(extended_reader<vector_reader>);
static_assert(seekable_reader<vector_reader>);

static_assert(reader<span_reader>);
static_assert(extended_reader<span_reader>);
static_assert(seekable_reader<span_reader>);

static_assert(writer<buffer_writer>);
// static_assert(writer<stream_writer>);
// static_assert(reader<stream_reader>);

} // namespace serializer